from flask import Flask, render_template, request, jsonify
from pymongo import MongoClient
from bson import json_util
import json

app = Flask(__name__, static_folder='static', template_folder='templates')

# 连接 MongoDB
try:
    client = MongoClient('mongodb://localhost:27017/')
    db = client['LGW']  # 数据库名
    collection = db['product']  # 集合名
except Exception as e:
    print(f"无法连接到 MongoDB: {e}")

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/api/products')
def get_products():
    page = int(request.args.get('page', 1))
    limit = int(request.args.get('limit', 25))
    skip = (page - 1) * limit
    
    # 获取搜索参数
    search_query = request.args.get('search', '')
    category_query = request.args.get('category', '')
    min_price = request.args.get('minPrice', '')
    max_price = request.args.get('maxPrice', '')
    price_none = request.args.get('priceNone', '').lower() == 'true'  # 是否搜索价格为 None 的商品
    features_json = request.args.get('features', '')
    
    # 解析特性参数
    features = []
    if features_json:
        try:
            features = json.loads(features_json)
        except:
            pass
    
    # 构建查询条件
    query = {}
    
    # 基本搜索查询 - 在产品名称中搜索
    if search_query:
        query["name"] = {"$regex": search_query, "$options": "i"}
    
    # 添加类别搜索条件
    if category_query:
        query["category"] = {"$regex": category_query, "$options": "i"}
    
    # 添加价格搜索条件
    price_conditions = []
    
    # 如果指定搜索价格为 None 的商品
    if price_none:
        price_conditions.append({"$or": [
            {"price": None},
            {"price": {"$exists": False}},
            {"price": ""},
            {"price": "None"},
            {"price": "null"}
        ]})
    
    # 如果设置了价格区间，则搜索有价格且在区间内的商品
    if min_price != '' or max_price != '':
        # 使用 $expr 和 $convert 来处理字符串类型的价格比较
        expr_conditions = []
        if min_price != '':
            expr_conditions.append({"$gte": [{"$convert": {"input": "$price", "to": "double", "onError": -1}}, float(min_price)]})
        if max_price != '':
            expr_conditions.append({"$lte": [{"$convert": {"input": "$price", "to": "double", "onError": -1}}, float(max_price)]})
        
        if expr_conditions:
            # 确保价格字段存在且不为空
            price_conditions.append({
                "$and": [
                    {"price": {"$exists": True}},
                    {"price": {"$ne": None}},
                    {"price": {"$ne": ""}},
                    {"price": {"$ne": "None"}},
                    {"price": {"$ne": "null"}},
                    {"$expr": {"$and": expr_conditions}}
                ]
            })
    
    # 如果有价格条件，添加到查询中
    if price_conditions:
        if len(price_conditions) == 1:
            query.update(price_conditions[0])
        else:
            # 如果有多个价格条件，使用 $or 连接（搜索价格为 None 的商品或价格在区间内的商品）
            if "$or" not in query:
                query["$or"] = price_conditions
            else:
                # 如果查询中已经有 $or，需要合并
                if "$and" not in query:
                    query["$and"] = [{"$or": query["$or"]}]
                query["$and"].append({"$or": price_conditions})
                del query["$or"]
    
    # 添加特性搜索条件
    if features:
        for feature in features:
            feature_name = feature.get('name', '')
            feature_value = feature.get('value', '')
            
            if feature_name or feature_value:
                feature_query = {"$elemMatch": {}}
                
                if feature_name and not feature_value:
                    # 只按特性名称搜索 - 支持模糊搜索
                    # 使用 $where 进行模糊匹配，匹配所有包含该名称的特性键
                    # 由于 MongoDB 的限制，我们使用 $where 来匹配动态键名
                    # 转义 JavaScript 字符串中的特殊字符（用于 indexOf 匹配）
                    escaped_name = feature_name.replace("\\", "\\\\").replace("'", "\\'").replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
                    search_pattern = escaped_name.lower()
                    # 使用 $where 进行模糊匹配
                    if "$where" not in query:
                        query["$where"] = f"""
                            function() {{
                                if (!this.feature || !Array.isArray(this.feature)) return false;
                                for (var i = 0; i < this.feature.length; i++) {{
                                    var item = this.feature[i];
                                    if (typeof item === 'object' && item !== null) {{
                                        for (var key in item) {{
                                            if (key.toLowerCase().indexOf('{search_pattern}') !== -1) {{
                                                return true;
                                            }}
                                        }}
                                    }}
                                }}
                                return false;
                            }}
                        """
                    else:
                        # 如果已经有 $where，需要合并条件
                        old_where = query["$where"]
                        query["$and"] = [
                            {"$where": old_where},
                            {"$where": f"""
                                function() {{
                                    if (!this.feature || !Array.isArray(this.feature)) return false;
                                    for (var i = 0; i < this.feature.length; i++) {{
                                        var item = this.feature[i];
                                        if (typeof item === 'object' && item !== null) {{
                                            for (var key in item) {{
                                                if (key.toLowerCase().indexOf('{search_pattern}') !== -1) {{
                                                    return true;
                                                }}
                                            }}
                                        }}
                                    }}
                                    return false;
                                }}
                            """}
                        ]
                        del query["$where"]
                        
                elif feature_value and not feature_name:
                    # 只按特性值搜索 - 使用正则表达式匹配任意键值对中的值
                    feature_query["$elemMatch"]["$or"] = [
                        {"峰值功率：": {"$regex": feature_value, "$options": "i"}},
                        {"传输距离：": {"$regex": feature_value, "$options": "i"}},
                        {"外壳材质：": {"$regex": feature_value, "$options": "i"}},
                        {"使用时长：": {"$regex": feature_value, "$options": "i"}},
                        {"装箱数量：": {"$regex": feature_value, "$options": "i"}},
                        {"输入电压：": {"$regex": feature_value, "$options": "i"}},
                        {"产品重量：": {"$regex": feature_value, "$options": "i"}},
                        {"供电方式：": {"$regex": feature_value, "$options": "i"}},
                        {"产品尺寸：": {"$regex": feature_value, "$options": "i"}},
                        {"彩盒尺寸：": {"$regex": feature_value, "$options": "i"}},
                        {"功能：": {"$regex": feature_value, "$options": "i"}},
                        {"配件：": {"$regex": feature_value, "$options": "i"}}
                    ]
                    if "feature" not in query:
                        query["feature"] = feature_query
                    else:
                        # 如果已经有其他条件，使用 $and
                        if "$and" not in query:
                            query["$and"] = [{"feature": query["feature"]}]
                        query["$and"].append({"feature": feature_query})
                        del query["feature"]
                        
                elif feature_name and feature_value:
                    # 同时按特性名称和值搜索 - 特性名称支持模糊搜索
                    # 转义 JavaScript 字符串中的特殊字符
                    escaped_name = feature_name.replace("\\", "\\\\").replace("'", "\\'").replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
                    escaped_value = feature_value.replace("\\", "\\\\").replace("'", "\\'").replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r')
                    search_name_pattern = escaped_name.lower()
                    search_value_pattern = escaped_value.lower()
                    # 使用 $where 进行模糊匹配
                    if "$where" not in query:
                        query["$where"] = f"""
                            function() {{
                                if (!this.feature || !Array.isArray(this.feature)) return false;
                                for (var i = 0; i < this.feature.length; i++) {{
                                    var item = this.feature[i];
                                    if (typeof item === 'object' && item !== null) {{
                                        for (var key in item) {{
                                            if (key.toLowerCase().indexOf('{search_name_pattern}') !== -1) {{
                                                var value = String(item[key] || '');
                                                if (value.toLowerCase().indexOf('{search_value_pattern}') !== -1) {{
                                                    return true;
                                                }}
                                            }}
                                        }}
                                    }}
                                }}
                                return false;
                            }}
                        """
                    else:
                        # 如果已经有 $where，需要合并条件
                        old_where = query["$where"]
                        query["$and"] = [
                            {"$where": old_where},
                            {"$where": f"""
                                function() {{
                                    if (!this.feature || !Array.isArray(this.feature)) return false;
                                    for (var i = 0; i < this.feature.length; i++) {{
                                        var item = this.feature[i];
                                        if (typeof item === 'object' && item !== null) {{
                                            for (var key in item) {{
                                                if (key.toLowerCase().indexOf('{search_name_pattern}') !== -1) {{
                                                    var value = String(item[key] || '');
                                                    if (value.toLowerCase().indexOf('{search_value_pattern}') !== -1) {{
                                                        return true;
                                                    }}
                                                }}
                                            }}
                                        }}
                                    }}
                                    return false;
                                }}
                            """}
                        ]
                        del query["$where"]
    
    # 执行查询
    # 如果设置了价格筛选条件（包括价格区间或搜索 None），则按价格降序排序
    use_aggregation = (min_price != '' or max_price != '' or price_none) and "$where" not in query
    
    if use_aggregation:
        # 使用聚合管道进行排序，确保：
        # 1. 有价格的商品按价格从高到低排序
        # 2. 价格为 None 的商品排在最后
        pipeline = [
            {"$match": query},
            {"$addFields": {
                "priceNum": {
                    "$cond": {
                        "if": {
                            "$and": [
                                {"$ne": ["$price", None]},
                                {"$ne": ["$price", ""]},
                                {"$ne": ["$price", "None"]},
                                {"$ne": ["$price", "null"]}
                            ]
                        },
                        "then": {
                            "$convert": {
                                "input": "$price",
                                "to": "double",
                                "onError": -999999999  # 无法转换的价格使用一个很小的负数，排在最后
                            }
                        },
                        "else": -999999999  # None 价格也使用这个值，排在最后
                    }
                }
            }},
            {"$sort": {"priceNum": -1}},  # 按价格从高到低排序
            {"$facet": {
                "data": [{"$skip": skip}, {"$limit": limit}, {"$project": {"priceNum": 0}}],
                "total": [{"$count": "count"}]
            }}
        ]
        result = list(collection.aggregate(pipeline))
        if result and result[0].get("data"):
            products = result[0]["data"]
            total = result[0]["total"][0]["count"] if result[0]["total"] else 0
        else:
            products = []
            total = 0
    else:
        # 如果使用了 $where，不能使用聚合管道，需要先查询再排序
        all_products = list(collection.find(query))
        
        # 如果设置了价格筛选条件，进行排序
        if min_price != '' or max_price != '' or price_none:
            def get_price_num(price):
                """将价格转换为数字，用于排序"""
                if price is None or price == "" or price == "None" or price == "null":
                    return -999999999
                try:
                    return float(price)
                except:
                    return -999999999
            
            # 按价格从高到低排序
            all_products.sort(key=lambda x: get_price_num(x.get('price')), reverse=True)
        
        # 计算总数
        total = len(all_products)
        
        # 分页
        products = all_products[skip:skip + limit]
    
    # 转换 ObjectId 为字符串，并处理 feature 字段
    for product in products:
        product['_id'] = str(product['_id'])
        # 将 feature 数组转换为字典
        if 'feature' in product and isinstance(product['feature'], list):
            features_dict = {}
            for item in product['feature']:
                if isinstance(item, dict):
                    # 处理字典类型的特性
                    for key, value in item.items():
                        # 如果用户指定了要显示的特性名称，则只保留这些特性
                        should_include = True
                        if features:
                            # 获取非空的特性名称列表
                            feature_names = [f.get('name') for f in features if f.get('name')]
                            if feature_names:
                                # 只有当当前特性名称在用户指定的列表中时才包含
                                should_include = any(name in key for name in feature_names)
                        
                        if should_include:
                            features_dict[key] = value
            product['feature'] = features_dict
        elif 'feature' in product:
            # 处理非数组类型的特性
            product['feature'] = str(product['feature'])
    
    return jsonify({
        'products': products,
        'total': total,
        'page': page,
        'limit': limit,
        'pages': (total + limit - 1) // limit
    })

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)